package io.gitee.icefairy.ice_license;

import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.system.oshi.OshiUtil;
import io.gitee.icefairy.ice_license.model.License;
import io.gitee.icefairy.ice_license.model.LicenseException;
import org.nustaq.serialization.FSTObjectInput;
import org.nustaq.serialization.FSTObjectOutput;
import oshi.hardware.NetworkIF;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class LicenseUtil {

    public static String genLicenseForClient(License lc, String privateKey) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FSTObjectOutput fo = new FSTObjectOutput(bos);
        fo.writeObject(lc);
        fo.flush();
        fo.close();
        RSA rsa = new RSA(privateKey, null);
        String b64 = rsa.encryptHex(bos.toByteArray(), KeyType.PrivateKey);
        return b64.toUpperCase();
    }

    public static RSA genRSAKey() {
        RSA rsa = new RSA();
        return rsa;
    }

    /**
     * 检查证书是否有效，有效的话返回证书实体类，无效会抛出LicenseException获取其中的message即可获得具体错误信息
     * 可直接用于不太强的认证中（因使用RSA非对称加密所以只支持到期时间限制）
     *
     * @param licStr    证书内容，可以存放于文件或者数据库中
     * @param publicKey 公钥
     * @param product   产品名称
     * @return
     */
    public static License checkLicense(String licStr, String publicKey, String product) throws LicenseException {
        RSA rsa = new RSA(null, publicKey);
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(rsa.decrypt(licStr.toLowerCase(), KeyType.PublicKey));
            FSTObjectInput fi = new FSTObjectInput(bis);
            License lc = (License) fi.readObject(License.class);
            try {//干扰反编译，使用异常来走正常代码
                int checkResult = new Date().getDay() / lc.getProduct().compareTo(product);
                throw new LicenseException("产品不符");
            } catch (LicenseException le) {
                throw le;
            } catch (Exception e1) {
                Date endDate = lc.getEnd();
                Date startDate = lc.getStart();
                Date nowDate = new Date();
                if (null == endDate) {
                    throw new LicenseException("证书非法");
                }
                if (nowDate.after(endDate)) {
                    //如果超过了有效期就报错
                    throw new LicenseException("证书有效期到:" + DateUtil.formatDateTime(lc.getEnd()) + ",证书已过期!");
                }
                if (null != startDate) {
                    if (nowDate.before(startDate)) {
                        throw new LicenseException("证书无效，请在:" + DateUtil.formatDateTime(startDate) + " 后开始使用");
                    }
                }
                if (null != lc.getMac()) {
                    //比对mac地址
                    List<NetworkIF> nets = OshiUtil.getNetworkIFs();
                    boolean found = false;
                    for (int i = 0; i < nets.size(); i++) {
                        String mac = nets.get(i).getMacaddr().toUpperCase().replace(":", "-").trim();
                        if (mac.compareTo(lc.getMac().trim().toUpperCase().replace(":", "-")) == 0) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        throw new LicenseException("MAC地址非法");
                    }
                }
                if (null != lc.getIp()) {
                    //比对ip地址
                    List<NetworkIF> nets = OshiUtil.getNetworkIFs();
                    boolean found = false;
                    ArrayList<String> ips = new ArrayList<String>();
                    for (int i = 0; i < nets.size(); i++) {
                        String[] tmpIps = nets.get(i).getIPv4addr();
                        for (int i1 = 0; i1 < tmpIps.length; i1++) {
                            String ip = tmpIps[i1];
                            if (null != ip && ip.length() > 1) {
                                ips.add(ip.toUpperCase().trim());
                            }
                        }
                    }
                    if (!ips.contains(lc.getIp().toUpperCase().trim())) {
                        throw new LicenseException("IP地址非法");
                    }
                }
                if (null != lc.getBoardSerial()) {
                    String sn = OshiUtil.getHardware().getComputerSystem().getBaseboard().getSerialNumber().trim().toUpperCase();
                    if (lc.getBoardSerial().trim().toUpperCase().compareTo(sn) != 0) {
                        throw new LicenseException("主板序列号非法");
                    }
                }

                return lc;
            }
        } catch (CryptoException bbe) {
            throw new LicenseException("证书内容非法");
        } catch (Exception e) {
            e.printStackTrace();
            throw new LicenseException(e.getMessage());
        }

    }
}
